/**
 * Trabalho 2 de Programacao Concorrente.
 * Prof. Dr. Julio Estrella
 * 
 * Determinacao da ocorrencia de palindromos e
 * calculo de numeros primos.
 * 
 * Grupo 07 - Turma B
 * Fabio de Albuquerque Dela Antonio 6792558
 * Leonardo Henrique Omoto 6793160
 * Pedro Paulo Canto Martucci 6793100
 * 
 * parser.c
 */

#include "../include/header.h"
#include "../include/parser.h"
#include "../include/palindromo.h"

/* Tamanho do buffer de palavras (vetor com ponteiros para palavras) [para cada iteracao do pipeline do OpenMP para o caso 1] */
#define TAM_BUFFER_PALAVRAS 10000

/* Utilizada no começo do método 1 para ajustar o ponteiro de cada rotina paralela para o comeco de uma palavra */
int ajustaPonteiroPalavra(char * fp, int tam, int * start, int end) {
    
    char c;
    int pos = (*start);
    int terminou = 0;

    /* Nao ajusta para comeco do arquivo. */
    if((*start) == 0)
        return 0;
   
    if(pos < tam && pos < end)
    {
        /* Provavelmente caiu no meio de uma palavra, entao le ate o final e descarta esta. */
        while(!terminou && pos < tam)
        {    
            /* le um caractere do arquivo e armazena em c */
            c = fp[pos];
            pos++;
            
            /* verifica se a posicao atual do ponteiro no arquivo nao ultrapassou o fim */
            if(pos >= end)
                return 1;
            /* se for um caractere valido, retorna 1 */
            if(!isalnum(c))
            {
                terminou = 1;    
            }
            
        }
        
        (*start) = pos;
    }       
    else 
    {
        fprintf(stderr, "Nao foi possivel ajustar ponteiro de arquivo para este processo.\n");
        return 1;
    }
    
    return 0;
}

/* Utilizada no comeco do metodo 2 apra ajustar o ponteiro de cada rotina paralela para o comeco de uma frase */
int ajustaPonteiroFrase(char *fp, int tam, int * start, int end) {
    
    char c;
    int terminou = 0, pos = (*start);
    
    /* Nao ajusta para comeco do arquivo. */
    if((*start) == 0)
        return 0;
    
    if(pos < tam && pos <= end) {
 
        /* Provavelmente caiu no meio de uma palavra, entao le ate o final e descarta esta. */
        while(!terminou && pos < tam) {    
            /* le um caractere do arquivo e armazena em c */
            c = fp[pos];
            pos++;
            
            /* verifica se a posicao atual do ponteiro no arquivo nao ultrapassou o fim */
            if(pos >= end)
                return 1;
            
            /* se for um caractere valido, retorna 1 */
            if(!isValid(c))
                terminou = 1;    
        }
        
        (*start) = pos;
        
    } else {
        fprintf(stderr, "Nao foi possivel ajustar ponteiro de arquivo para este processo.\n");
        return 1;
    }
    
    return 0;
}

/* Le as proximas palavras do arquivo e as retornam */
char ** parseProxPalavras(char * in, int tam, int * start, int end, int *nPalavras) {

    int size;

    #ifdef PARALELO
    size = 3000;
    #else
    size = 10000000;
    #endif
    
    char ** palavras = (char **)malloc(size*sizeof(char *));
    #ifndef MAPEIA_BUFFER
    char * palavra = (char *)calloc(PAL_MAX_SIZE,sizeof(char));
    #endif
    char c;
    int i = 0, j = 0, pos = (*start), offset = 0;
    
    #ifndef MAPEIA_BUFFER
    if(palavra == NULL) {
        fprintf(stderr, "Memoria insuficiente.\n");
        exit(1);        
    }
    #endif
    
    if(palavras == NULL) {
        fprintf(stderr, "Memoria insuficiente.\n");
        exit(1);
    }

    if(pos < tam && pos <= end)
    {
        while(pos <= tam) {    
            /* le um caractere do arquivo e armazena em c */
            c = in[pos];
            pos++;
            
            /* verifica se o caractere e alfanumerico
             * em caso positivo, ele e armazenado na string palavra */	
            if(isalnum(c)) {
                #ifndef MAPEIA_BUFFER
                palavra[i++] = c;
                #else
                i++;
                #endif
            }
                
            /* caso nao seja alfanumerico, e ja foi lido algum caractere valido, 
             * termina-se a palavra */
            else if(i > 0)
            {   
                #ifndef MAPEIA_BUFFER
                palavra[i] = '\0';
                palavras[j++] = palavra;
                #else
                in[pos-1] = '\0';
                palavras[j++] = (char *)(in + pos - 1 - i);
                #endif           
                
                offset += i;
                
                if(j >= size) {
                    palavras = (char **)realloc((void *)palavras, sizeof(char *)*(j+100));	
                    size = (j+100);
                }
                
                if(palavras == NULL) {
                    fprintf(stderr, "Impossivel realocar vetor de palavras.\n");
                    exit(1);
                }

                i = 0;

                #ifndef MAPEIA_BUFFER
                palavra = (char *)calloc(PAL_MAX_SIZE,sizeof(char)); //
                
                if(palavra == NULL) {
                    fprintf(stderr, "Memoria insuficiente.\n");
                    exit(1);
                }
                #endif

                #ifdef PARALELO
                if(pos >= end || offset >= TAM_BUFFER_PALAVRAS)
                    break;
                #else 
                if(pos >= tam)
                    break;
                #endif
            }
        }
        
        (*start) = pos; 
    }
    else
    {
        #ifndef MAPEIA_BUFFER
        free(palavra);
        #endif
        free(palavras);
        return NULL;
    }     

    *nPalavras = j;
    #ifndef MAPEIA_BUFFER
    free(palavra); 
    #endif
    return palavras;
}

/* le as proximas frases do arquivo e as retornam */
char ** parseProxFrases(char * in, int tam, int start, int end, int *nFrases) {
    
    int size = 10000;
    char ** frases = (char **)malloc(size*sizeof(char *));
    #ifndef MAPEIA_BUFFER
    char * frase = (char *)calloc(FRA_MAX_SIZE,sizeof(char));
    #endif
    char c;
    int i = 0, j = 0, pos = start;
    
    #ifndef MAPEIA_BUFFER
    if(frase == NULL) {
        fprintf(stderr, "Memoria insuficiente.\n");
        exit(1);
    }
    #endif
    
    if(frases == NULL) {
        fprintf(stderr, "Memoria insuficiente.\n");
        exit(1);
    }
    
    if(pos < tam && pos <= end)
    {
        while(pos <= tam)
        {     
            /* le um caractere do arquivo e armazena em c */
            c = in[pos];
            pos++;

            /* verifica se o caractere e valido
             * em caso positivo, ele e armazenado na string frase */	
            if(isValid(c))
                #ifndef MAPEIA_BUFFER
                frase[i++] = c;
                #else
                i++;
                #endif
                
            /* caso nao seja valido, e ja foi lido algum caractere valido, 
             * termina-se a frase */
            else if( i > 0)
            {
                #ifndef MAPEIA_BUFFER
                frase[i] = '\0';
                frases[j++] = frase;
                #else
                in[pos-1] = '\0';
                frases[j++] = (char *)(in + pos - 1 - i);
                #endif

                if(j >= size) {
                    frases = (char **)realloc((void *)frases, sizeof(char *)*(j+100));
                    size = j+100;
                }
                
                if(frases == NULL) {
                    fprintf(stderr, "Impossivel realocar vetor de palavras.\n");
                    exit(1);
                }

                i = 0;

                #ifndef MAPEIA_BUFFER
                frase = (char *)calloc(FRA_MAX_SIZE,sizeof(char));
                

                if(frase == NULL) {
                    fprintf(stderr, "Memoria insuficiente.\n");
                    exit(1);
                }
                #endif
                
                if ( pos > end ) break;
            }
        }
    }
    else
    {
        #ifndef MAPEIA_BUFFER
        free(frase);
        #endif
        free(frases);
        return NULL;
    }     
   
    *nFrases = j;
    #ifndef MAPEIA_BUFFER
    free(frase);
    #endif
    return frases; 
}

/*separa a frase em um vetor de palavras retorna o numero de palavras*/
char ** parsePalavraFrase(char * frase, int * tam) {
    
    char ** palavras = (char **)malloc(sizeof(char *));
    char * palavra;
    (*tam) = 1;
    
    if(palavras == NULL) {
        fprintf(stderr, "Memoria insuficiente.\n");
        exit(1);
    }
    
    int i = 0, j;
    int terminou = 0;
    
    while(!terminou) {
    
        palavra = (char *)malloc(PAL_MAX_SIZE*sizeof(char));
    
        if(palavra == NULL) {
            fprintf(stderr, "Memoria insuficiente.\n");
            exit(1);
        }
        
        j = 0;
        
        /* Le uma palavra */
        while(isalnum(frase[i])) {
            
            palavra[j++] = frase[i++];
            
            if(j >= PAL_MAX_SIZE) {
                fprintf(stderr, "Palavra muito grande.\n");
                exit(1);
            }
            
            /* Terminou de ler a frase. */
            if(i >= strlen(frase) || frase[i] == '\0') {
                terminou = 1;
                break;
            }
        }
        
        /* Armazena a palavra no vetor de strings. */
        palavra[j] = '\0';
        palavras[*tam - 1] = palavra;
        
        
        /* Consome caracteres nao validos */
        if(!terminou)
            while(!isalnum(frase[i])) {
                /* Terminou de ler a frase. */
                if(i >= strlen(frase) || frase[i] == '\0') {
                    terminou = 1;
                    break;
                }
                i++;
            }
        
        /* Se tiver mais palavras, aumenta tamanho do vetor de strings. */
        if(!terminou) {
            (*tam)++;
            palavras = (char **)realloc((void *)palavras, sizeof(char *)*(*tam));
            
            if(palavras == NULL) {
                fprintf(stderr, "Impossivel realocar vetor de palavras de uma frase.\n");
                exit(1);
            }
        }
    }
        
    return palavras;
}

/* Converte uma palavra em um inteiro */
int convertePalavraInteiro(char * palavra) {
    int soma = 0;
    int i;
    int tam = strlen(palavra);
    
    for(i = 0; i < tam && palavra[i] != '\0'; i++)
        if(isalnum(palavra[i]))
            soma += palavra[i];
        
    return soma;
}

/* Obtem tamanho do arquivo. */
long fileSize(FILE * in) {
    long pos_atual = ftell(in);
    long ret;
    
    fseek(in, 0, SEEK_END);
    
    ret = ftell(in);
    
    fseek(in, pos_atual, SEEK_SET);    
    
    return ret;
}

